﻿namespace ScrumLite.Data.Tests
{
    using System;
    using System.Collections.Generic;
    using System.Transactions;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    /// <summary>
    /// Summary description for CommitmentStoreFixture
    /// </summary>
    [TestClass]
    public class CommitmentStoreFixture
    {
        ICommitmentStore store;
        private Guid projectId = new Guid("1C4F9968-8D5E-4d8a-9BD8-9A8DF1434B5A");

        [TestInitialize]
        public void Initialize()
        {
            this.store = new CommitmentStore();
        }

        [TestMethod()]
        public void ShouldReturnStandupDatesForColoradoProject()
        {
            string projectUri = "12184E41-B84D-4c2f-9251-CB0F8E8D7DDB";
            IList<DateTime> dates = this.store.RetrieveStandupDates(new Guid(projectUri));

            Assert.AreEqual(20, dates.Count);
            Assert.AreEqual(new DateTime(2008, 2, 1), dates[0].Date);
        }

        [TestMethod()]
        public void ShouldGetCommitmentsForColoradoProjectAndForSpecificDate()
        {
            using (TransactionScope scope = new TransactionScope())
            {
                CreateFakeCommitmentsStore();
                DateTime standUpDate = DateTime.Today;

                Commitment[] actual = this.store.RetrieveCommitments(standUpDate, projectId);

                Assert.AreEqual(3, actual.Length);
                Assert.AreEqual(standUpDate, actual[0].createdOn);
            }
        }

        [TestMethod]
        public void ShouldUpdateCommitmentTwiceAndNotThrowConflictException()
        {
            using (TransactionScope scope = new TransactionScope())
            {                
                Commitment c = new Commitment()
                {
                    id = Guid.NewGuid(),
                    fk_project = MockHelpers.KnownProjectId,
                    user_createdBy = "John",
                    createdOn = DateTime.Now,
                    remaining = (decimal?)0.5,
                    verification = "verification",
                    spent = (decimal?)0.5,
                    title = "Title",
                    initialEstimate = 1,
                };

                this.store.Add(c);

                c.initialEstimate = null;
                
                this.store.Update(c);

                this.store.RetrieveCommitment(c.id);

                Assert.IsNull(c.initialEstimate);
            }
        }

        [TestMethod()]
        public void ShouldNotInsertCommitmentWithNonExistingProjectAndThenInsertCorrectOne()
        {
            Commitment commitment = new Commitment()
            {
                id = Guid.NewGuid(),
                user_createdBy = "Unit Test User",
                fk_project = Guid.NewGuid(),
                createdOn = DateTime.Now,
                remaining = 10,
                verification = "Test results OK",
                spent = 5,
                title = "Run unit test for adding a new commitment"
            };

            using (TransactionScope scope = new TransactionScope())
            {
                try
                {
                    this.store.Add(commitment);
                }
                catch (System.Data.SqlClient.SqlException ex)
                {
                    Assert.IsNotNull(ex);
                }
                commitment.fk_project = MockHelpers.KnownProjectId;
                this.store.Add(commitment);
                Assert.IsNotNull(this.store.RetrieveCommitment(commitment.id));
            }
        }

        [TestMethod()]
        public void ShouldRetrieveDailyCommitmentsCount()
        {
            using (TransactionScope scope = new TransactionScope())
            {
                CreateFakeCommitmentsStore();
                DateTime standUpDate = new DateTime(2008, 2, 1);
                bool closed = true;

                Dictionary<DateTime, int> actual = this.store.RetrieveDailyCommitmentsCount(projectId, closed);

                Assert.IsNotNull(actual);
                Assert.AreEqual(1, actual.Count);
                Assert.AreEqual(3, actual[DateTime.Today]);
            }
        }

        [TestMethod()]
        public void ShouldDeleteCommitment()
        {
            Guid c1Id = new Guid("1F4F9968-8D5E-4d8a-9BD8-9A8DF1434B5A");
            using (TransactionScope scope = new TransactionScope())
            {
                CreateFakeCommitmentsStore();
                this.store.Delete(c1Id);

                Assert.IsNull(this.store.RetrieveCommitment(c1Id));

                Commitment[] actual = this.store.RetrieveCommitments(DateTime.Today,projectId);
                Assert.AreEqual(2, actual.Length);

                foreach (Commitment c in actual)
                {
                    Assert.IsFalse(c.id == c1Id);
                }
            }
        }

        private static void CreateFakeCommitmentsStore()
        {
            Guid projectId = new Guid("1C4F9968-8D5E-4d8a-9BD8-9A8DF1434B5A");
            Guid c1Id = new Guid("1F4F9968-8D5E-4d8a-9BD8-9A8DF1434B5A");

            using (ScrumLiteDataContext context = new ScrumLiteDataContext())
            {
                Project project = new Project() { endsOn=DateTime.Today, id = projectId, name = "FakeProject", security_group ="", startsOn=DateTime.Today, uri_repository="", user_ownedBy="" };
                context.Projects.InsertOnSubmit(project);

                Commitment commitment1 = new Commitment() { createdOn = DateTime.Today, fk_project = projectId, id = c1Id, spent= 10, initialEstimate=0, remaining=0, title="commitment1", verification="commitment1", user_createdBy="" };
                Commitment commitment2 = new Commitment() { createdOn = DateTime.Today, fk_project = projectId, id = Guid.NewGuid(), spent = 10, initialEstimate = 0, remaining = 0, title = "commitment2", verification = "commitment2", user_createdBy = "" };
                Commitment commitment3 = new Commitment() { createdOn = DateTime.Today, fk_project = projectId, id = Guid.NewGuid(), spent = 10, initialEstimate = 0, remaining = 0, title = "commitment3", verification = "commitment3", user_createdBy = "" };
                
                context.Commitments.InsertOnSubmit(commitment1);
                context.Commitments.InsertOnSubmit(commitment2);
                context.Commitments.InsertOnSubmit(commitment3);

                context.SubmitChanges();
            }
        }
    }
}
